package com.atguigu.spzx.manager.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.util.IdUtil;
import com.atguigu.spzx.manager.interceptor.LoginAuthInterceptor;
import com.atguigu.spzx.manager.mapper.SysUserMapper;
import com.atguigu.spzx.manager.service.SysUserService;
import com.atguigu.spzx.model.common.Result;
import com.atguigu.spzx.model.common.ResultCodeEnum;
import com.atguigu.spzx.model.dto.sys.LoginDto;
import com.atguigu.spzx.model.dto.sys.SysUserDto;
import com.atguigu.spzx.model.entity.sys.SysUser;
import com.atguigu.spzx.model.exception.SpzxException;
import com.atguigu.spzx.model.vo.sys.LoginVo;
import com.atguigu.spzx.model.vo.sys.ValidateCodeVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class SysUserServiceImpl implements SysUserService {
    @Resource
    SysUserMapper sysUserMapper;
    @Resource
    RedisTemplate redisTemplate;
    @Override
    public LoginVo login(LoginDto loginDto) {
        String userName = loginDto.getUserName();
        String password = loginDto.getPassword();
        String code = loginDto.getCode();
        String codeKey = loginDto.getCodeKey();
        if(StringUtils.isEmpty(code)||
                StringUtils.isEmpty(codeKey)){
            throw new SpzxException(ResultCodeEnum.LOGIN_CODE_ERROR , null);

        }
        if(StringUtils.isEmpty(userName)||
            StringUtils.isEmpty(password)){
            throw new SpzxException(ResultCodeEnum.LOGIN_ERROR , null);
        }
        //0、校验验证码
        Object codeObj = redisTemplate.opsForValue().get("sys:user:code:" + codeKey);
        if(codeObj==null || !code.equals(codeObj.toString())){
            //验证码错误
            throw new SpzxException(ResultCodeEnum.LOGIN_CODE_ERROR , null);
        }
        //1、根据账号查询管理员用户信息
        SysUser sysUser = sysUserMapper.findSysUserByUsername(userName);
        //2、如果查询失败 返回账号错误
        if(sysUser==null){
            throw new SpzxException(201,"账号错误" , null);
        }
        //3、使用传入的密码 加密后和查询到的管理员用户的密码比较
        //数据库中密码使用了spring提供的MD5加密工具加密
        String inputPwd = DigestUtils.md5DigestAsHex(password.getBytes());
        //4、如果密码错误 返回密码错误
        if(!StringUtils.equals(sysUser.getPassword(),inputPwd)){
            throw new SpzxException(201,"密码错误" ,null);
        }
        //5、生成token ：token映射 查询到的管理员用户对象
        //hutool工具包可以通过工具类生成19位长度的唯一的按时间顺序递增的id
        String token = IdUtil.createSnowflake(1, 1).nextIdStr();
        //存到redis中保持登录状态: 设置7天的过期时间
        sysUser.setPassword(null);
        //redisTemplate存储自定义类型的对象时 必须实现序列化接口
        // 通过图形化工具 查看redisTemplate序列化的对象时 数据不可读
        redisTemplate.opsForValue().set("sys:user:login:"+token,
                sysUser , 7 , TimeUnit.DAYS);
        //给redisTemplate设置键(使用字符串直接存) 和 值(转为json直接存) 的序列化器工具
        //6、创建LoginVo携带前端需要的参数返回
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setRefresh_token("1");
        //删除图片验证码的缓存
        redisTemplate.delete("sys:user:code:" + codeKey);
        return loginVo;
    }

    @Override
    public ValidateCodeVo genValidateCodeImg() {
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(120, 50, 4, 16);
        String image = lineCaptcha.getImageBase64();
        String code = lineCaptcha.getCode();
        String token = IdUtil.createSnowflake(1, 1).nextIdStr();
        redisTemplate.opsForValue().set("sys:user:code:"+token , code , 10 , TimeUnit.MINUTES);

        ValidateCodeVo validateCodeVo = new ValidateCodeVo();
        validateCodeVo.setCodeImg(image);
        validateCodeVo.setCodeKey(token);
        return validateCodeVo;
    }

    @Override
    public SysUser getUserInfo() {
//        Object sysUser = redisTemplate.opsForValue().get("sys:user:login:" + token);
//        if(sysUser==null){
//            throw new SpzxException(ResultCodeEnum.LOGIN_EXPIRE_ERROR , null);
//        }

//        return LoginAuthInterceptor.CACHE_MAP.get(Thread.currentThread());
        return LoginAuthInterceptor.THREAD_LOCAL.get();
    }

    @Override
    public void logout(String token) {
        redisTemplate.delete("sys:user:login:" + token);
    }

    @Override
    public PageInfo<SysUser> page(Integer pageNum, Integer pageSize, SysUserDto sysUserDto) {
        PageHelper.startPage(pageNum,pageSize);
        List<SysUser> sysUserList = sysUserMapper.findPageByCondition(sysUserDto);
        return new PageInfo<>(sysUserList);
    }

    @Override
    public void deleteById(Long id) {
        sysUserMapper.deleteById(id);
    }

    @Override
    public SysUser getById(Long id) {

        return sysUserMapper.findById(id);
    }

    @Override
    public void updateById(SysUser sysUser) {
        //校验账号是否被占用
        // 使用id查询当前用户的数据判断 账号是否修改
        // 如果修改了 再判断修改后的账号是否被占用(使用修改后的查询)
        sysUser.setUpdateTime(new Date());
        sysUserMapper.updateById(sysUser);
    }

    @Override
    public void save(SysUser sysUser) {
        //参数判断
        String username = sysUser.getUsername();
        String password = sysUser.getPassword();
        if(StringUtils.isEmpty(username)||
                StringUtils.isEmpty(password)){
            throw new SpzxException(ResultCodeEnum.ERROR,null);
        }
        //账号是否被占用
        int count = sysUserMapper.selectCountByUsername(username);
        if(count>0){
            //账号被占用
            throw  new SpzxException(ResultCodeEnum.USERNAME_EXISTS_ERROR,null);
        }
        sysUser.setCreateTime(new Date());
        sysUser.setUpdateTime(new Date());
        //密码加密
        String digestAsHex = DigestUtils.md5DigestAsHex(sysUser.getPassword().getBytes());
        sysUser.setPassword(digestAsHex);
        sysUserMapper.save(sysUser);
    }
}
